from django.conf import settings
from rest_framework import serializers
from .models import User
import re
from django_redis import get_redis_connection


# serializers.ModelSerializer
# serializers.Serializer

class RegisterUserSerializer(serializers.ModelSerializer):
    # 短信字段 如何生成???
    # 用户名,密码,手机号
    # 确认密码,短信,是否同意协议

    # password2 只能是写入,不能将这个数据转换为JSON
    password2 = serializers.CharField(label='确认密码', write_only=True, allow_blank=False, allow_null=False)
    sms_code = serializers.CharField(label='短信', write_only=True, allow_blank=False, allow_null=False)
    allow = serializers.CharField(label='是否同意协议', write_only=True, allow_blank=False, allow_null=False)

    token = serializers.CharField(label='token', read_only=True)

    class Meta:
        model = User
        # 因为 ModelSerializer 是根据 fileds字段来生成 序列化的字段的,
        # 首先先看模型中是否有对应的字段,如果有自动生成
        # 如果没有 看我们自己是否实现了,如果没有实现就报错了
        fields = ['username', 'password', 'mobile', 'password2', 'sms_code', 'allow', 'token']

        # 如何区设置 自动生成的字段的选项???
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }



        # 对数据的校验 有 4中方式
        # 1. 字段类型
        # 2. 选项
        # 3. 单个字段校验 , 单个字段的值我们可以实现 验证    def validate_filename
        # 4. 多个字段校验

    # 手机号的验证
    def validate_mobile(self, value):
        # value 就是传递过来的值

        if not re.match('1[3-9]\d{9}', value):
            raise serializers.ValidationError('手机号不符合规则')

        # 如果满足条件就把值返回就可以
        return value

    def validate_allow(self, value):

        # 验证
        # 要求前段 传递一个字符串
        if value != 'true':
            raise serializers.ValidationError('没有同意协议')

        return value

    # 多个字段校验 是指我们需要用到多个 值
    def validate(self, attrs):

        # 密码和确认密码需要比多

        password = attrs.get('password')
        password2 = attrs.get('password2')

        if password != password2:
            raise serializers.ValidationError('密码不一致')

        # 短信校验

        # 1. 获取用户提交的短信验证码
        sms_code = attrs.get('sms_code')
        mobile = attrs.get('mobile')
        # 2. 获取redis中验证码
        redis_conn = get_redis_connection('code')

        redis_code = redis_conn.get('sms_%s' % mobile)

        if redis_code is None:
            raise serializers.ValidationError('验证码已过期')

        # 3. 比较
        # 注意事项: redis的数据是 bytes类型
        if redis_code.decode() != sms_code:
            raise serializers.ValidationError('验证码不正确')

        return attrs

    # 当序列化器调用 save方法的时候 会自动调用 序列化器中的 create方法,将数据保存到数据库中

    def create(self, validated_data):

        # User.objects.create(**validate_data)

        # validated_data 校验之后的数据

        # 父类方法不能满足我们的需求,我们就需要重写
        # 因为 validated_data 有6个字段
        # 实际入库是3个字段
        # 我们需要将多余的字段删除
        del validated_data['sms_code']
        del validated_data['allow']
        del validated_data['password2']

        # 处理之后的字段是可以入库的
        user = super().create(validated_data)

        # user的密码还是明文
        user.set_password(validated_data['password'])
        user.save()

        # 这里是 数据入库,并且修改密码的地方,我们生成一个token,然后再把token经过序列化返回给客户端
        # jwt 的token如何生成呢?

        from rest_framework_jwt.settings import api_settings

        # 需要获取2个方法
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # 将用户的信息放到 payload中
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # token 就是生成好的 jwt token
        user.token = token

        return user


class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'mobile', 'email', 'email_active')


class EmailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'email')
        extra_kwargs = {
            'email': {
                'required': True
            }
        }

        # 保存邮箱信息就是在 update方法中

    def update(self, instance, validated_data):
        # instance 对象
        # validated_data  验证之后的数据
        email = validated_data['email']
        instance.email = email
        instance.save()

        # 在这里发送激活邮件
        # from django.core.mail import send_mail
        # subject, message, from_email, recipient_list,html_message=None
        # subject = '美多商城激活邮件'
        # message = ''
        # from_email = settings.EMAIL_FROM #发件人
        # recipient_list = [email]  #收件人列表
        # 可以传递 html代码
        # 我们需要生成一个url,这个url中的token需要包含用户的id信息(id需要被处理)

        # url = instance.generic_verify_url()

        # html_message= '<p>尊敬的用户您好！</p>' \
        #            '<p>感谢您使用美多商城。</p>' \
        #            '<p>您的邮箱为：%s 。请点击此链' \
        #               '接激活您的邮箱：</p>' \
        #            '<p><a href="%s">%s<a></p>' % (email, url, url)

        # send_mail(subject,message,from_email,recipient_list)

        url = instance.generic_verify_url()
        from celery_tasks.email.tasks import send_verify_email

        send_verify_email.delay(email, url)
        return instance


class UserListSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username']


from goods.models import SKU


class UserHistorySerializer(serializers.Serializer):
    sku_id = serializers.CharField(label='商品id', required=True)

    # 检验sku_id是否存在
    def validate_sku_id(self, value):
        try:
            SKU.objects.get(pk=value)
        except SKU.DoesNotExist:
            raise serializers.ValidationError('商品不存在')
        return value

    def create(self, validated_data):
        # create方法会将sku_id入库,但是现在我们重写了这个方法,应该让 sku_id保存在redis中
        # 1.连接redis
        redis_conn = get_redis_connection('history')
        sku_id = validated_data.get('sku_id')
        user = self.context['request'].user
        # 2.保存到redis中，首先要去重
        # 2.1  先将保存的数据删除
        redis_conn.lrem('history_%s' % User.id, 0, sku_id)
        # 2.2  在添加
        redis_conn.lpush('history_%s' % user.id, sku_id)
        # 2.3 只保留5条记录
        # 对一个列表进行修剪（trim） 就是说    让列表只保留指定区间内的元素
        redis_conn.ltrim('history_%s' % user.id, 0, 4)
        return validated_data


class SKUSerialzier(serializers.ModelSerializer):
    class Meta:
        model = SKU
        fields = ('id', 'name', 'price', 'default_image_url', 'comments')
